package com.miaosha.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.miaosha.entity.MiaoShaGoods;
import com.miaosha.entity.vo.OrderVo;
import com.miaosha.mapper.MiaoShaGoodsMapper;
import com.miaosha.rabbitmq.RabbitMQSender;
import com.miaosha.service.MiaoShaGoodsService;
import com.miaosha.utils.CommonResult;
import com.miaosha.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;

import static com.miaosha.utils.RedisConstants.*;


@Slf4j
@Service("miaoShaGoodsService")
public class MiaoShaGoodsServiceImpl extends ServiceImpl<MiaoShaGoodsMapper, MiaoShaGoods> implements MiaoShaGoodsService {

    @Resource
    private MiaoShaGoodsMapper miaoShaGoodsMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RabbitMQSender rabbitMQSender;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final DefaultRedisScript<Long> SECKILL_SCRIPT;
    static {
        SECKILL_SCRIPT = new DefaultRedisScript<>();
        SECKILL_SCRIPT.setLocation(new ClassPathResource("seckill.lua"));
        SECKILL_SCRIPT.setResultType(Long.class);
    }

    @Override
    public List<MiaoShaGoods> listAllNow() {
        return miaoShaGoodsMapper.listAllNow();
    }

    @Override
    public MiaoShaGoods findById(Integer id) {
        return miaoShaGoodsMapper.findById(id);
    }

    @Override
    public int update(MiaoShaGoods miaoShaGoods) {
        return miaoShaGoodsMapper.updateById(miaoShaGoods);
    }

    @Override
    public void add2Redis(MiaoShaGoods miaoShaGoods) {

        String goodsId = miaoShaGoods.getId().toString();

        long time = (miaoShaGoods.getEndTime().getTime() - System.currentTimeMillis()) / 1000;

//        Gson gson = new Gson();
//        RedisUtil.setKey(SECKILL_GOODS_KEY + goodsId, gson.toJson(miaoShaGoods));
//        RedisUtil.setKeyTime(SECKILL_GOODS_KEY + goodsId, time);

        // 保存库存
        RedisUtil.setKey(SECKILL_STOCK_KEY + goodsId, miaoShaGoods.getStock().toString());
        RedisUtil.setKeyTime(SECKILL_STOCK_KEY + goodsId, time);

        // 保存开始时间
        RedisUtil.setKey(SECKILL_BEGIN_KEY + goodsId, String.valueOf(miaoShaGoods.getStartTime().getTime()));
        RedisUtil.setKeyTime(SECKILL_BEGIN_KEY + goodsId, time);

    }

    @Override
    public void removeRedis(Long[] miaoShaGoodsIds) {
        for(Long id : miaoShaGoodsIds) {
            RedisUtil.delKey(SECKILL_STOCK_KEY + id);
            RedisUtil.delKey(SECKILL_BEGIN_KEY + id);
        }
    }

    @Override
    public CommonResult<String> doSeckill(Integer miaoShaGoodsId, Long userId) {

        Integer voucherId = miaoShaGoodsId;

        String stockKey = SECKILL_STOCK_KEY + voucherId;
        // 0.1 秒杀商品不存在情况
        // 商品不存在和超出时间为一种情况
        boolean exist = RedisUtil.existKey(stockKey);
        if(!exist) {
            log.info("redis中不存在秒杀商品---------------------------------");
            return CommonResult.error(204, "商品不存在或已过期！");
        }
        // 0.2 秒杀商品超出秒杀时间情况
        String goodsKey = SECKILL_BEGIN_KEY + voucherId;
        long beginTime = Long.parseLong(RedisUtil.getKeyValue(goodsKey));
        long time = System.currentTimeMillis() - beginTime;
        if(time<=0) {
            log.info("秒杀未开始！---------------------------------");
            return CommonResult.error(204, "秒杀未开始！");
        }

        // 1.执行lua脚本
        Long result = stringRedisTemplate.execute(
                SECKILL_SCRIPT,
                Collections.emptyList(),
                voucherId.toString(), userId.toString());

        assert result != null;
        int r = result.intValue();
        // 2.判断结果是否为0
        if(r!=0) {
            // 2.1结果不为0没有秒杀资格
            log.info("库存不足，或用户不能重复下单---------------------------------");
            String msg = r==1 ? "库存不足" : "不能重复下单";
            return CommonResult.error(204, msg);
        }
        // 3.生成订单
        // 3.1设置下单用户id
        OrderVo orderVo = new OrderVo();
        orderVo.setUserId(userId);
        orderVo.setMiaoShaGoodsId(miaoShaGoodsId);
        // 3.2异步下单
        rabbitMQSender.send(RedisUtil.entityToJson(orderVo));
        return CommonResult.success("抢购成功，前往支付！");
    }
}
